#!/usr/bin/env python
# coding: utf-8
"""
pyCharter.py -- Creating a graph image or URL by GoogleChart

  Google Chart API document -- http://code.google.com/apis/chart/

Usage:
-------
>>> foo = pyCharter(pyCharter.PIE_CHART_3D, (300,300), "Hello World")
>>> bar = ("Hello", 60)
>>> baz = ("World", 40)
>>> foo.putData(bar)
>>> foo.putData(baz)
>>> url = foo.get_url()
>>> png_image = foo.getPNG()

  <label name>:data1,data2,... (comma separated)
-------

The MIT License

Copyright (c) 2008 hkato193

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
"""
import re
import string

class pyCharter(object):
    """
    pyCharter.py -- Creating a graph image/URL by GoogleChart
    """ 
    LINE_CHART = "lc"
    XY_PLOT = "lxy"
    BAR_CHART_H = "bhs"
    BAR_CHART_V = "bvs"
    PIE_CHART = "p"
    PIE_CHART_3D = "p3"

    def __init__(self, type=LINE_CHART, size=(450,200), title=""):
        """
        Initialize pyCharter object with a data .
        
            type : Graph type(Use constant defined in this module.
            size : Graph size. It should be array of x,y pixel
            title : Graph title(if needed).
        """
        trans_tbl = string.maketrans(" ","+")
        self._title = string.translate(title, trans_tbl)
        self._size = size
        self.set_type(type)
        self._data = {}

    def set_title(self, new_title=""):
        """
        Set or change a graph title.
        """
        trans_tbl = string.maketrans(" ","+")
        self._title = string.translate(title, trans_tbl)

    def set_type(self, new_type=LINE_CHART):
        """
        Set or change a graph type.
        """
        self._type = new_type
        if new_type == self.PIE_CHART or new_type == self.PIE_CHART_3D:
            self._add_data_func = self.__create_pie_data__
        else:
            self._add_data_func = self.__create_normal_data__

    def put_data(self, legend, data):
        """
        putData(self, legend, dataI

        Set data stored by the legend.
        
            legend : legend of data.
            data : ARRAY of data.

        If this method is called with the same legend multiple times,
        the data is appended to the same legend.
        """
        if legend not in self._data:
            self._data[legend] = []            
        for value in data:
            self._data[legend].append(value)

    def get_png(self):
        """
        get_png(self) -> PNG image

        Get image(as PNG) by using Google chart.
        """
        import urllib2
        try:
            url = self.get_url()
            http_hndl = urllib2.urlopen(url)
        except Exception, e:
            print "Error while parsing data."
            print " --", e
            return None
        except urllib2.HTTPError, e:
            print "Error while getting data."
            if e.code == 400:
                print " --", e
                print "    -- Fix it & try again."
            else:
                print " --", e
            e.close()
            return None
        img = http_hndl.read()
        http_hndl.close()
        return img

    def get_url(self):
        """
        get_url(self) -> string

        Get URL string of current holding data.
        """
        if len(self._data.values()) == 0:
            raise Exception("Number of data is 0. What shoud I do?")

        # Create URL.
        url = 'http://chart.apis.google.com/chart?'
        url += "chs=" + str(self._size[0]) + "x" + str(self._size[1])
        if self._title != "":
            url += '&chtt=' + self._title
        url += self._add_data_func()
        url += '&cht='+self._type
        return url

    def __create_normal_data__(self):
        """
        Internal method to create data part in a url.
        This is for normal graph types.
        """
        url_val = '&chd=t:'
        url_legend = '&chdl='
        for legend,data in self._data.iteritems():
            url_legend += legend + '|'
            val_str = ""
            for value in data:
                val_str += str(value) + ','
            url_val += val_str[:-1] + '|'
        return url_val[:-1] + url_legend[:-1]

    def __create_pie_data__(self):
        """
        Internal method to create data part in a url.
        This is for pie chart types.
        """
        url_val = '&chd=t:'
        url_label = '&chl='
        for label,data in self._data.iteritems():
            url_label += label + '|'
            url_val += str(data[0]) + ','
        return url_val[:-1] + url_label[:-1]

if __name__ == '__main__':
    a = pyCharter(pyCharter.PIE_CHART_3D, (450,200), 'Test Graph')
    a.put_data("Hello", [60,20,0,40])
    a.put_data("World", [40,50,100,30])
    print a.get_url()
    img = a.get_png()
    if img:
        file = open('dummy.png', 'wb')
        file.write(img)
        file.close()

    a.set_type(pyCharter.LINE_CHART)
    print a.get_url()

    img = a.get_png()
    if img:
        file = open('dummy2.png', 'wb')
        file.write(img)
        file.close()

